// PalmMsg.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#pragma warning(disable: 4311 4244)	// 4244 4267

#include "MsgVolParser.h"

FILE		*istream;
BYTE		last_type;
int			total_SMS_successful_read;
int			total_SMS;
errno_t		last_err;

errno_t	msgvolparser_getlasterr (void) {
	return last_err;
}
//
//	Init function: Open PalmMsgV001 to read
//	In:	Filename of PalmMsgV001
//	Re:	 0 - File open error
//		>0 - Success
int	msgvolparser_init(const char *strVolFile) {
	int rc;
	errno_t	err;
	if( ( err = fopen_s( &istream, strVolFile, "rb") ) != 0 ) {
	// Not opened
		printf("ERROR: Unable to find PalmMsgV001 under current directory!\n");
		rc = 0;
	} else {
	// Opened
		rc = (int)istream;
	}
	last_err = 0;
	last_type = 0;
	total_SMS = 0;
	total_SMS_successful_read = 0;
	return rc;
}
//
void msgvolparser_deinit(void) {
	if (istream!=NULL) {
		fclose(istream);
	}
}
//
//	Locate to begin of next SMS Header
//	Re:	 0 - EOF reached
//		>0 - Header position in file
int msgvolparser_locate_next_SMS_Header (void) {
	int rc = 0;
	BYTE lBuf[PARSER_BUFFER_SIZE], *c, *end, c1, c2;
	size_t readbytes; 
	do {
		readbytes = fread ( lBuf, sizeof(BYTE), PARSER_BUFFER_SIZE, istream);
		if (readbytes == PARSER_BUFFER_SIZE) {
			end = lBuf + PARSER_BUFFER_SIZE - PARSER_ROLLBACK;
			for (c = lBuf; c < end; c++) {
				c1 = *(c+1);
				c2 = *(c+2);
				if ( *c == (BYTE)0x27 && c1 == (BYTE)0x15 && 
						( c2 == (BYTE)0x11 || c2 == (BYTE)0x12 ||
						c2 == (BYTE)0x22 ) ) {
					fseek(istream, c - end, SEEK_CUR);
					rc = (int)c2;
					break;
				}
			}
			if ( rc == 0 ) {	// Not found
				fseek(istream,-2,SEEK_CUR);
			} else {
				last_type = rc;
				break;
			}
		} else {
#ifdef PM_DEBUG
			printf ("Error: Locate next SMS Header - EOF reached...\n");	
#endif
			rc = RC_ERROR;
			break;
		}
	} while (!feof(istream));
	return rc;
//  0 ---- EOF REACHED
//	1 ---- INBOX	27 15 22
//  2 ---- OUTBOX	27 15 11 - 27 14 21 - 51 1C
//	3 ---- SENT		27 15 11 - 27 14 21 - 51 27
//  4 ---- SAVED	27 15 12
//  5 ---- DRAFTED	27 15 11
//	6 ---- OTHER_UNKNOWN_TYPE
}
//
//	Analyse sms string and set SMS structure
//	In:	pSMS - Pointer to SMS struct for output
//	Re:	 0 - Error
//		>0 - Success, return SMS type
int msgvolparser_analyse_sms_packet (s_SMS_t *pSMS) {
	int rc = 0;
	BYTE bType, lBuf[5];
	total_SMS++;
#ifdef PM_DEBUG
	int fPos;
	fPos = ftell(istream);
#endif
	msgbody_reset(pSMS);
	fread(&bType,sizeof(BYTE),1,istream);	// READ TYPE
#ifdef PM_DEBUG
		printf ("Parsing SMS %3d from %6XH: TYP=%2XH\n",
				total_SMS, fPos, bType);
#endif
	if (bType == 0x22) {	// INBOX
		rc = msgvolparser_readas_type1 (pSMS);
	} else if (bType == 0x11) {
		lBuf[0] = 0x27; lBuf[1] = 0x14; lBuf[2] = 0x21;
		if (msgvolparser_locate_next_Header(lBuf,3)==-1) {
			rc = 0;
		} else {
			rc = msgvolparser_readas_type23(pSMS);
		}
	} else if (bType == 0x12) {
		rc = msgvolparser_readas_type4 (pSMS);
	} else {
#ifdef PM_DEBUG
		printf ("Parsing ERROR! Unknow SMS type at %6XH: TYP=%2XH\n",
				fPos, bType);
#endif
		rc = 0;
	}
	if (rc > 0)
		total_SMS_successful_read++;
#ifdef PM_DEBUG
	pSMS->dbg_SMS_serial = total_SMS;
#endif
	return rc;
}
//
//	TESTED AT 2009.4.12 - OK
int msgvolparser_readas_type1 (s_SMS_t *pSMS) {
	BYTE lBuf[5];
	msgvolparser_skip_bytes(3);	// SKIP PB
	if (msgvolparser_read_vardata((BYTE*)pSMS->tch_content,MAX_CONTENT_SIZE,2)==RC_ERROR) {
		return 0;	// Read UD data interupted.
	}
	lBuf[0] = 0x51; lBuf[1] = 0x09;
	if (msgvolparser_checkbytes(lBuf,2)==RC_ERROR) {
		return 0;	// Wrong UDEP
	}
	msgvolparser_skip_bytes(8);	// SKIP MID
	msgvolparser_skip_bytes(26);	// SKIP MID
	lBuf[0] = 0x27; lBuf[1] = 0x14; lBuf[2] = 0x21;
	if (msgvolparser_checkbytes(lBuf,3)==RC_ERROR) {
		pSMS->type_SMS = 6;
		return 6;	// This is a deleted record, return succesfull but nothing written. 
	}
	msgvolparser_skip_bytes(4);	// SKIP PB
	if (msgvolparser_read_vardata((BYTE*)pSMS->tch_SMStele,MAX_STRING_SIZE)==RC_ERROR) {
		msgvolparser_skip_bytes(34);	// Tweak!
#ifdef PM_DEBUG
		printf ("Tweak: Try to recover from unknown data...\n");
#endif
		if (msgvolparser_checkbytes(lBuf,3)==RC_ERROR) {
			pSMS->type_SMS = 6;
			return 6;	// This is a deleted record, return successful but nothing written. 
		}
		msgvolparser_skip_bytes(4);	// SKIP PB
		if (msgvolparser_read_vardata((BYTE*)pSMS->tch_SMStele,MAX_STRING_SIZE)==RC_ERROR) {
			return 0;	// Read MN error.
		}
	}
	msgvolparser_skip_bytes(2);	// SKIP PB
	msgvolparser_preread_fixdata(lBuf,2,0);
	if ((lBuf[0] != 0x40) || ((lBuf[1] & 0xF0)!=0x40)) {
		pSMS->type_SMS = 6;
		return 6;	// This is a deleted record, return successful but nothing written. 
	}
	msgvolparser_skip_bytes(10);	// SKIP IMID
	lBuf[0] = 0x11; lBuf[1] = 0x2A;
	if (msgvolparser_checkbytes(lBuf,2)==RC_ERROR) {
		pSMS->type_SMS = 6;
		return 6;	// This is a deleted record, return successful but nothing written. 
	}
	pSMS->type_SMS = 1;
	return 1;	// Return 1 for INBOX read succesfull!
};

int msgvolparser_readas_type23 (s_SMS_t *pSMS) {
	int rc = 0;
	BYTE lBuf[5];
	msgvolparser_skip_bytes(7);	// SKIP PB
	if (msgvolparser_read_vardata((BYTE*)pSMS->tch_SMStele,MAX_STRING_SIZE)==RC_ERROR) {
		return 0;	// Read MN data interupted.
	}
	msgvolparser_skip_bytes(2);	// SKIP PB
	msgvolparser_preread_fixdata(lBuf,2,0);
	if ((lBuf[0] != 0x40) || ((lBuf[1] & 0xF0)!=0x40)) {
		return 0;
	}	
	msgvolparser_skip_bytes(8);	// SKIP PB
	msgvolparser_preread_fixdata(lBuf,2,0);
	if ((lBuf[0] == 0x51) && (lBuf[1] == 0x1C)) {	// TYPE 2
		lBuf[0] = 0xFF; lBuf[1] = 0xFF; lBuf[2] = 0x22;
		if (msgvolparser_locate_next_Header(lBuf,3)==-1) {
			return 0;	
		}
		msgvolparser_skip_bytes(6);
		if (msgvolparser_read_vardata((BYTE*)pSMS->tch_content,MAX_CONTENT_SIZE,2)==RC_ERROR) {
			return 0;	// Read UD data interupted.
		}
		lBuf[0] = 0x51; lBuf[1] = 0x09;
		if (msgvolparser_checkbytes(lBuf,2)==RC_ERROR) {
			return 0;	// Wrong UDEP
		}
		pSMS->type_SMS = 2;
		rc = 2;
	} else if ((lBuf[0] == 0x51) && (lBuf[1] == 0x27)) {	// TYPE 3
		lBuf[0] = 0xFF; lBuf[1] = 0xFF; lBuf[2] = 0x22;
		if (msgvolparser_locate_next_Header(lBuf,3) == -1) {
			return 0;
		}
		msgvolparser_skip_bytes(6);
		if (msgvolparser_read_vardata((BYTE*)pSMS->tch_content,MAX_CONTENT_SIZE,2)==RC_ERROR) {
			return 0;	// Read UD data interupted.
		}
		msgvolparser_skip_bytes(12);
		lBuf[0] = 0x11; lBuf[1] = 0x2A;
		if (msgvolparser_checkbytes(lBuf,2)==RC_ERROR) {
			return 0;	// Wrong UDEP
		}
		pSMS->type_SMS = 3;
		rc = 3;
	} else {
		return 0;
	}
	return rc;
}
//
// TO BE TESTED
int msgvolparser_readas_type5 (s_SMS_t *pSMS) {
	BYTE lBuf[5];
	msgvolparser_skip_bytes(5);
	if (msgvolparser_read_vardata((BYTE*)pSMS->tch_content,MAX_CONTENT_SIZE,2)==RC_ERROR) {
		return 0;	// Read UD data interrupted.
	}
	lBuf[0] = 0x11; lBuf[1] = 0x2A;
	if (msgvolparser_checkbytes(lBuf,2)==RC_ERROR) {
		return 0;
	}
	pSMS->type_SMS = 5;
	return 5;
}
//
// TO BE TESTED
int msgvolparser_readas_type4 (s_SMS_t *pSMS) {
	BYTE lBuf[5];
	lBuf[0] = 0x02;	lBuf[1]=0x22;
	if (msgvolparser_checkbytes(lBuf,2)==RC_ERROR) {
		return 0;
	}
	msgvolparser_skip_bytes(3);	// SKIP MID
	if (msgvolparser_read_vardata((BYTE*)pSMS->tch_content,MAX_CONTENT_SIZE,2)==RC_ERROR) {
		return 0;	// Read UD data interrupted.
	}
	lBuf[0] = 0x51; lBuf[1] = 0x09;
	if (msgvolparser_checkbytes(lBuf,2)==RC_ERROR) {
		return 0;	// Wrong UDEP
	}
	pSMS->type_SMS = 4;
	return 4;
}
//
//	Skip n bytes in istream
//	In:	iBytes - Number of bytes to skip
void msgvolparser_skip_bytes (int iBytes) {
	if (fseek(istream,iBytes,SEEK_CUR)!=0) {
#ifdef PM_DEBUG
		printf ("Error: Skip %d bytes exceed feof!", iBytes);
#endif
	}
}
//
//	Read n bytes in istream but don't change file read cursor!
//	In:	pBuf - Buffer to store read data
//		iBytes - Number of bytes to read
//	Re:	 0 - Read error
//		>0 - Bytes read.
int msgvolparser_preread_fixdata (BYTE *pBuf, size_t iBytes, int rollback) {
	int rc;
	size_t readbytes;
	readbytes = fread(pBuf,sizeof(BYTE),iBytes,istream);
	rc = (readbytes < iBytes ? 0 : (int)readbytes);
#ifdef PM_DEBUG
	if (rc == 0) {
		printf ("Error: Preread fixdata %d bytes exceeds feof, %d actual read.\n", 
				iBytes, readbytes);
	}
#endif
	if (rollback == 1) {
		fseek(istream,-(int)readbytes,SEEK_CUR);
	}
	return rc;
}
//
//	Read 1st bytes as data size and read remaining data.
//	In:	pBuf - Buffer to store read data
//		sizeof_pBuf - Size of read buffer
//	Re:	 0 - Read error
//		>0 - Bytes read.
int msgvolparser_read_vardata (BYTE *pBuf, size_t sizeof_pBuf, int lBytes) {
	int rc;
	size_t iLen;
	BYTE bLen;
	WORD wLen;
	size_t readbytes;
	if (lBytes == 1) {
		fread(&bLen,sizeof(BYTE),1,istream);
		iLen = (int)bLen;
	} else {
		fread(&wLen,sizeof(BYTE),2,istream);
		bLen = wLen & 0xFF;
		iLen = (int)((wLen>>8) + (bLen<<8));
	}
	if (iLen <= sizeof_pBuf) {
		readbytes = fread(pBuf,sizeof(BYTE),iLen,istream);
#ifdef PM_DEBUG
		printf ("Ready to read %d (%XH) Bytes.\n", iLen, iLen);
#endif
		if (readbytes == iLen) {
			rc = (int)iLen;
		} else {
			rc = 0;
#ifdef PM_DEBUG
		printf ("Error: Read vardata %dB exceeds file end! %dB read\n", 
			iLen, readbytes);
#endif
		}
	} else {
		rc = 0;
#ifdef PM_DEBUG
		printf ("Error: Memory not sufficient! %d(%XH) < %d(%XH)\n", 
			sizeof_pBuf, sizeof_pBuf, iLen, iLen);
#endif
	}
	return rc;
};
//
//	Check next bytes is identical to mark bytes
//	In:	pCB - Input mark string
//		sizeof_pCB - Length of imput mark string
//	Re:	 0 - Not same
//		>0 - Same
int	msgvolparser_checkbytes (const BYTE *pCB, size_t sizeof_pCB) {
	int rc = 0;
	BYTE lBuf[8];
	size_t readbytes;
	readbytes = fread(lBuf,sizeof(BYTE),sizeof_pCB,istream);
	if (readbytes == sizeof_pCB) {
		rc = memcmp(lBuf,pCB,sizeof_pCB);
		if ( rc == 0 ) {
			rc = 1;
		} else {
#ifdef PM_DEBUG
			printf ("Error: Check bits not identical:");
			readbytes = 0;
			do {
				printf(" %02XH|%02XH", pCB[readbytes], lBuf[readbytes]);	
				readbytes ++;
			} while (readbytes < sizeof_pCB);
			printf ("\n");
#endif
			rc = 0;
		}
	} else {
#ifdef PM_DEBUG
		printf ("Error: Read checkdata %dB exceeds file end! %dB read\n", 
			sizeof_pCB, readbytes);
#endif
		rc = 0;
	}
	return rc;
}
//
void msgvolparser_print_read_results (void) {
	printf ("Total %d SMS alike record found, %d successfully exported.\n", 
		total_SMS, total_SMS_successful_read);	
}
//
int msgvolparser_locate_next_Header (const BYTE *pCB, size_t sizeof_pCB) {
	int rc = 0;
	BYTE lBuf[PARSER_BUFFER_SIZE], *c, *end, c1, c2;
	size_t readbytes;
	if ((sizeof_pCB == 2) || (sizeof_pCB == 3)){
		do {
			readbytes = fread ( lBuf, sizeof(BYTE), PARSER_BUFFER_SIZE, istream);
			if  (readbytes == PARSER_BUFFER_SIZE) {
				end = lBuf + PARSER_BUFFER_SIZE - PARSER_ROLLBACK;
				for (c = lBuf; c < end; c++) {
					c1 = *(c+1);
					c2 = *(c+2);
					if ((*c == *pCB) && (c1 = *(pCB+1)) && 
							((sizeof_pCB==2) || (c2=*(pCB+2)))) {
						fseek(istream, c-end-PARSER_ROLLBACK, SEEK_CUR);
						rc = (int)sizeof_pCB;
						break;
					} else if ((*c==0x27)&&(c1=0x15)) {
						fseek(istream, c-end-PARSER_ROLLBACK, SEEK_CUR);
						rc = -1;
						#ifdef PM_DEBUG
							printf ("Error: Locate next Header - SMS Head reached...\n");
						#endif
						break;
					}
				}
				if (rc == 0) {
					fseek(istream, -2, SEEK_CUR);
				} else {
					break;
				}
			} else {
#ifdef PM_DEBUG
				printf ("Error: Locate next Header - EOF reached...\n");	
#endif
			}
		} while (!feof(istream));
	} else {
#ifdef PM_DEBUG
		printf ("Error: Locate next Header don't support str longer than 3.\n");
#endif
	}
	return rc;
}